#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

#include "app_context.h"
#include "util.h"

#define ENABLE_AIQ
#define ENABLE_NPU // 启用NPU功能

// Global quit flag, accessible by the signal handler
volatile bool g_quit = false;


static void sigint_handler(int signo)
{
    (void)signo;
    printf("\nCaught signal %d, exiting gracefully...\n", signo);
    g_quit = true;
}

// --- Application Lifecycle Functions ---

void config_load_defaults(app_config_t *config)
{
    // V4L2 Configuration
    config->video_device      = "/dev/video64";
    config->capture_width     = 1920;
    config->capture_height    = 1080;
    config->capture_format    = V4L2_PIX_FMT_NV12;
    config->buffer_count      = 4;

    // DRM Configuration
    config->drm_module        = "rockchip";
    config->drm_format        = DRM_FORMAT_NV12;

    // AIQ Configuration
    config->sensor_entity_name = "m02_b_imx219 6-0010";
    config->iq_files_path     = "/etc/iqfiles/";

    // RKNN Configuration
    config->rknn_model_path   = "./best8s.rknn";
}

// --- Initialization and Cleanup ---

static int initialize_modules(app_context_t *app_ctx)
{
    app_config_t *config = &app_ctx->config;

    // V4L2 Initialization
    app_ctx->v4l2_ctx.device = (char*)config->video_device;
    app_ctx->v4l2_ctx.width = config->capture_width;
    app_ctx->v4l2_ctx.height = config->capture_height;
    app_ctx->v4l2_ctx.in_fourcc = config->capture_format;
    app_ctx->v4l2_ctx.buffer_count = config->buffer_count;
    if (v4l2_init(&app_ctx->v4l2_ctx) != 0) return -1;

    // DRM Initialization
    app_ctx->drm_ctx.module = (char*)config->drm_module;
    app_ctx->drm_ctx.width = config->capture_width;
    app_ctx->drm_ctx.height = config->capture_height;
    app_ctx->drm_ctx.out_fourcc = config->drm_format;
    app_ctx->drm_ctx.buffer_count = config->buffer_count;
    if (drm_init(&app_ctx->drm_ctx) != 0) return -1;

    // Create shared DMABUF buffers
    if (drm_create_buffers(&app_ctx->drm_ctx, config->capture_width, config->capture_height) != 0) return -1;

#ifdef ENABLE_AIQ
    // AIQ Initialization
    app_ctx->aiq_ctx = aiq_init(config->sensor_entity_name, config->iq_files_path, config->capture_width, config->capture_height);
    if (!app_ctx->aiq_ctx) return -1;
#endif

#ifdef ENABLE_NPU
    // RKNN Engine Initialization
    if(rknn_engine_init(&app_ctx->rknn_engine_ctx, config->rknn_model_path) != 0) return -1;

    // RGA Initialization (must be after RKNN)
    if(rga_init(&app_ctx->rga_ctx, &app_ctx->rknn_engine_ctx) != 0) return -1;
#endif

    // Pipeline Initialization
    if (pipeline_init(&app_ctx->pipeline_ctx, &app_ctx->v4l2_ctx, &app_ctx->drm_ctx, &app_ctx->rknn_engine_ctx, &app_ctx->rga_ctx, &g_quit) != 0) return -1;

    return 0;
}

static void cleanup_modules(app_context_t *app_ctx)
{
    // The order of cleanup is important: reverse of initialization
    pipeline_cleanup(&app_ctx->pipeline_ctx);

#ifdef ENABLE_NPU
    rga_deinit(&app_ctx->rga_ctx, &app_ctx->rknn_engine_ctx);
    rknn_engine_release(&app_ctx->rknn_engine_ctx);
#endif

#ifdef ENABLE_AIQ
    aiq_deinit(app_ctx->aiq_ctx);
#endif

    drm_cleanup(&app_ctx->drm_ctx);
    v4l2_cleanup(&app_ctx->v4l2_ctx);
}


// --- Main Execution ---

int main(void)
{
    app_context_t app_ctx;
    memset(&app_ctx, 0, sizeof(app_context_t));

    // Set up signal handler for graceful exit
    signal(SIGINT, sigint_handler);

    // Load configuration
    config_load_defaults(&app_ctx.config);

    // Initialize all modules
    if (initialize_modules(&app_ctx) != 0)
    {
        fprintf(stderr, "Failed to initialize application modules.\n");
        cleanup_modules(&app_ctx);
        return -1;
    }

    // Start video streaming and processing pipeline
    if (v4l2_stream_on(&app_ctx.v4l2_ctx, app_ctx.drm_ctx.buffers) != 0)
    {
        fprintf(stderr, "Failed to start V4L2 streaming.\n");
        cleanup_modules(&app_ctx);
        return -1;
    }

    if(pipeline_start(&app_ctx.pipeline_ctx) != 0)
    {
        fprintf(stderr, "Failed to start processing pipeline.\n");
        v4l2_stream_off(&app_ctx.v4l2_ctx);
        cleanup_modules(&app_ctx);
        return -1;
    }

    // Main loop - application runs here
    printf("Application running. Press Ctrl+C to exit.\n");
    while (!g_quit)
    {
        sleep(1);
    }

    // Stop pipeline and streaming
    pipeline_stop(&app_ctx.pipeline_ctx);
    v4l2_stream_off(&app_ctx.v4l2_ctx);

    // Clean up all resources
    cleanup_modules(&app_ctx);

    printf("Application exited cleanly.\n");
    return 0;
}
